home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PCMania 30
/
PCMania CD30.iso
/
sharewar
/
graphic
/
sprmaker
/
cargar.doc
< prev
next >
Wrap
Text File
|
1994-12-29
|
17KB
|
471 lines
¿ Como hacer un programa utilizando sprites?
Este texto pretende explicar como hacer programas
utilizando sprites, en el lenguaje Turbo Pascal, espero que
los programadores de Turbo C no tengan demasiados problemas a
la hora de adaptar las rutinas.
Prácticamente todos los juegos que existen en el mercado
están programados utilizando los modos gráficos de la vga, mas
concretamente el modo 320 x 200 x 256, pues bien, el primer
problema que nos encontramos a la hora de programar un juego,
o una utilidad con un entorno gráfico es la manera de activar
este modo, con los lenguajes de Borland podemos encontrar los
drivers que nos activaran los modos gráficos requeridos en
multitud de programas, pero no ( hasta la fecha ) los modos de
256 colores en vga o Svga, gracias al shareware se pueden
encontrar en el mercado unos drivers pensados para esto, yo en
concreto voy a utilizar el driver SVGA256.BGI de Jordan
Hargrave ( Hi, Jordan :-)), para registraros a este driver tan
solo tendréis que pagarle 20$ al autor, si bien también
podréis optar por otra opción, que seria activar la vga en ASM
o Ensamblador, esto es bien fácil con la interrupción 10h de
la bios, de esta forma MOV AX,0013h , INT 10h ya tendríamos la
vga 320x200x256 activada, pero no podremos contar con toda la
librería de gráficos que se nos suministra con el compilador,
aunque al programar todas las rutinas gráficas en ASM
tendremos algo de mas rapidez.
Pues bien, para activar la vga con el driver SVGA.BGI lo
primero que tendremos que hacer es decirle al compilador que
este driver no es de los que el lleva incorporado, si no que
es un driver de usuario ajeno al compilador, esto lo haremos
con el comando -> InstallUserDriver tal que así:
Driver:=InstallUserDriver('SVGA256',NIL); y luego
inicializando el modo con: Initgraph(Driver,graphmode,'');
donde graphmode puede ser un numero del 0 al 6 que representan
todos los modos de svga, de esta forma activaremos la svga
cargando el driver svga256.bgi del disco, pero existe una
forma mas profesional de hacer esto, que es incluir el driver
en tu mismo programa como un objeto, evitando que el driver
este en un fichero independiente, y tiempo de acceso al disco
dándole mas rapidez al programa a la hora de cargarse, esto lo
podemos conseguir convirtiendo el driver SVGA256.BGI a obj con
el comando que se incluye con vuestro compilador BINOBJ de
esta forma BINOBJ SVGA256.BGI SVGA256 SVGA256, ya tenemos el
driver como objeto, después solo nos queda añadir esta línea
en nuestro programa:
PROCEDURE SVGA256;EXTERNAL
{$L SVGA256.OBJ}
Y ya le tendremos en nuestro programa, para que todo os quede
mas claro os incluyo la unit que programe para Sprite Maker.
UNIT SVGA;
INTERFACE
const
XNOR_PUT = 5;
NOR_PUT = 6;
NAND_PUT = 7;
TRANS_COPY_PUT = 8;
PROCEDURE SVGA256;
PROCEDURE INICIA(GRAPHMODE:INTEGER);
IMPLEMENTATION
USES GRAPH;
VAR GRAPHDRIVER:INTEGER;
PROCEDURE SVGA256;EXTERNAL;
{$L SVGA256.OBJ}
PROCEDURE INICIA;
BEGIN
GRAPHDRIVER:=INSTALLUSERDRIVER('SVGA256',nil);
IF REGISTERBGIDRIVER(@SVGA256)<0 THEN HALT(1);
initgraph(graphdriver,graphmode,'');
END;
END.
Para usarla tan solo tendreis que incluirla en la linea de units del
programa principal, y llamar al procedimiento inicia en el momento que
deseis activar el modo grafico: INICIA(0) activara el modo 320x200x256.
Graphmode puede tomar estos valores:
0=320x200x256 VGA/MCGA
1=640x400x256 SVGA
2=640x480x256 SVGA
3=800x600x256 SVGA
4=1024x768x256 SVGA
5=640x350x256 SVGA
6=1280x1024x256 SVGA
Bueno, ya por fin podemos dedicarnos a los sprites ;-)
una vez que hemos activado los modos gráficos de la vga la
cosa es mas fácil, por lo menos en Turbo Pascal ya que podemos
usar todos los comandos de la unit graph, pero siempre queda
la opción de que nos programemos algunas rutinas en ASM para
darle mas rapidez al programa.
Lo primero que tenemos que saber de los sprites es como
cargarlos, o como incluirlos dentro del programa, para todo
esto son muy importantes los punteros sin tipo, que se
declaran como SPRITE:POINTER, ellos nos servirán para saber en
que posición de la memoria tenemos el dibujo que hay que
llevar a la memoria de pantalla, pero esto que suena un tanto
complicado no lo es, ahora lo veréis.
Para cargar un sprite utilizaremos el comando Blockread:
·BlockRead, procedimiento·
Lee e introduce uno o más registros en una variable.
Declaración:
procedure BlockRead(var F: File; var Buf; Count: Word [; var Result:
Word]);
donde:
F variable tipo fichero sin tipo
Buf cualquier variable
Count una expresión de tipo Word
Result una variable de tipo Word
Target:
Windows, Real, Protected
Observaciones:
F es una variable de tipo fichero sin tipo, Buf es cualquier variable, Count
es una expresiónde tipo Word, y Result es una variable de tipo Word.
BlockRead lee Count o menos registros del fichero F a la memoria, empezando
en el primer byte ocupado por Buf. El número verdadero de registros
completos leídos (menor o igual que Count) se devuelve en el parámetro
opcional Result. Si Result no se especifica, se produce un error E/S si el
número leído no es igual que Count.
El bloque transferido completo ocupa como mucho Count symbol * RecSize
bytes, siendo RecSize el tamaño de registro especificado cuando el fichero
fue abierto (o 128 si el tamaño de registro no se especificó). Se produce
error si Count symbol * RecSize es mayor que 65,535 (64K).
Result es un parámetro opcional. Si fue transferido el bloque completo,
Result será igual a Count. Si no, si Result es menor que Count, el final del
fichero fue alcanzado antes de que se completara la transferencia. En ese
caso, si el tamaño de registro del fichero es mayor que 1, Result devuelve
el númerode registros completos leídos.
La posición de fichero actual es adelantada Result registros a causa de
BlockRead.
Con {$I-}, IOResult devuelve 0 si la operación fue satisfactoria; si no,
devuelve un código de error distinto de cero.
Restricciones:
El fichero debe estar abierto.
El fichero primero tendremos que abrirlo con reset y
luego cargar todos los bytes que ocupa en una variable
dinámica con la ayuda de un puntero.
F1:='NOMBRE.SPR'; Le damos el nombre una variable string
ASSIGN(F,F1); asignamos este nombre a una variable
fichero
RESET(F,1); abrimos el fichero indicando que la lectura
será de un byte en un byte.
SIZE:=FILESIZE(F); obtenemos el tamaño del fichero
GETMEN(SPRITE,SIZE); y con el creamos una variable
dinámica utilizando el puntero
sprite.
BLOCKREAD(F,SPRITE^,SIZE,SIZE); y cargamos todo el dibujo
a esta variable.
CLOSE(F);
No os olvidéis de que para un correcto uso de la memoria
toda las variables dinámicas que dejen de ser útiles tendréis
que liberarlas o mejor dicho liberar esta memoria con freemen.
Ya lo tenemos en memoria, solo nos queda mostrarlo en
pantalla, para eso utilizaremos el comando PUTIMAGE, pero
antes vamos a ver como se puede incluir los sprites en el
mismo programa, creando un solo fichero ejecutable que
contenga todos los gráficos. Para esto os será muy útil el
apartado anterior de como incluir el driver SVGA256.BGI en tu
mismo programa, ya que el procedimiento es el mismo.
Ejemp: el sprite casa.spr lo queremos incluir en nuestro
programa, lo primero es convertirlo a objeto, así:
BINOBJ CASA.SPR CASA CASA
Ya esta, ahora le añadimos a nuestro programa la
siguiente línea.
PROCEDURE CASA;EXTERNAL;
{$L CASA.OBJ}
Y le asignamos un puntero:
SPRITE:=@CASA;
Ya esta listo para el siguiente paso, el de mostrarlo en
pantalla, como veis todos los sprites los utilizo con punteros
que indican la posición en memoria del dibujo, esto es lo mas
practico, porque un solo puntero puede servirnos para muchos
sprites, pero también podemos usar un array con el tamaño del
sprite en cuestión, ya que el comando putimage lo que necesita
es simplemente una variable que contenga el dibujo. Aquí
tenéis el comando PUTIMAGE y GETIMAGE:
·PutImage, procedimiento (Graph unit)·
Sitúa una imágen binaria en la pantalla.
Declaración:
procedure PutImage(X, Y: Integer; var BitMap; BitBlt: Word);
Target:
Real, Protected
Observaciones:
(X, Y) es la esquina superior izquierda de una región rectangular en la
pantalla. BitMap es un parámetro sin tipo que contiene la altura y la
anchura de la región, y la imágen binaria que será puesta en la pantalla.
BitBlt especifica que operador binario será usado para situar la imágen
binaria en la pantalla.
Cada constante corresponde a una operación binaria. Por ejemplo:
PutImage(X, Y, BitMap, NormalPut) pone la imágen almacenada en BitMap en (X,
Y) usando la instrucción de lenguaje de ensamblador MOV para cada byte en la
imágen.
PutImage(X, Y, BitMap, XORPut) pone la imágen almacenada en BitMap en (X, Y)
usando la instrucción de lenguaje de ensamblador XOR para cada byte en la
imágen. Esta es una técnica de animación usada a menudo para "arrastrar" una
imágen por la pantalla.
PutImage(X, Y, BitMap, NotPut) invierte los bits en BitMap y entonces pone
la imágen almacenada en BitMap en (X, Y) usando el lenguaje de ensamblador
MOV en la imágen. Así, la imágen aparece en vídeo inverso del BitMap
original.
Restricciones:
Debe usarse en modo gráfico.
·GetImage, procedimiento (Graph unit)·
Grava una imagen binaria de la región especificada en un buffer.
Declaración:
procedure GetImage(x1, y1, x2, y2: Integer; var BitMap);
Target:
Real, Protected
Observaciones:
X1, Y1, X2, y Y2 definen una región rectangular en la pantalla. BitMap es un
parámetro sin tipo que debe ser mayor o igual que 6 la cantidad de área
definida por la región. Las dos primeras palabras de BitMap almacenan la
altura y la anchura de la región. La tercera palabra está reservada.
El resto de BitMap se usa para grabar la imágen binaria en sí. Usar la
función ImageSize para determinar los requerimientos de tamaño de BitMap.
Restricciones:
Debe usarse en modo gráfico. la memoria necesaria para grabar la región debe
ser menos que 64K.
Así que para ver los sprites que anteriormente hemos
cargado solo tendremos que hacer:
PUTIMAGE(120,50,SPRITE^,NORMALPUT);
Y para leer una porción de un dibujo en pantalla:
GETIMAGEN(120,50,140,80,FONDO^);
Siendo fondo otro puntero.
Así el mover por la pantalla un sprite es bastante fácil:
x,y:word;
x:=10;
y:=20;
getimage(x,y,x+20,y+20,fondo^);
putimage(x,y,sprite^,trans_copy_put);
for x:=10 to 300 do
begin
putimage(x,y,fondo^,normalput);
getimage(x+1,y,x+21,y+20,fondo^);
putimage(x+1,y,sprite^,trans_copy_put);
end;
Si queréis que el movimiento sea mas rápido, tan solo tendréis
que decirle que de saltos de 2 o 4 en 4.
Para los que se decidan a programar en ASM os diré que el
sprite esta formado por:
4 bytes que representan:
Los primeros 2 un word o palabra que indica la longitud
del eje X.
Los siguientes 2 son el otro word que indica la longitud
del eje Y.
Todos los siguientes bytes son el dibujo, cada pixel es
un byte, ya que estamos trabajando con sprites de 256 colores
2^8, los X primeros bytes del dibujo corresponderán a este
eje, y se repetirán en número de Y.
Estos sprites pueden ser usados en cualquier modo de la
SVGA con 256 colores, a mayor resolución menor será el sprite.
¿Como cambio los colores?
Bien, llegados a este punto nos encontramos con que
podemos cargar sprites en nuestro programa, moverlos, etc,
pero tenemos un problema, los sprites no se ven con los mismos
colores que tenían en el programa Sprite Maker, eso es debido
a que el programa carga la paleta de colores para cada sprite,
pero vuestro programa no, y muestra los sprites con los
colores que tenía la vga en el momento de activarla, entonces
lo que tendremos que hacer será cargar la paleta original de
los sprites. Pero antes será mejor que aprendamos algo mas
sobre como trabaja la vga con estos colores.
Cuando nosotros activamos un punto la pantalla con algún
modo de la SVGA 256C, estamos escribiendo en la memoria de
pantalla un byte, osea 8 bits que pueden tener 2^8
convinaciones, lo que es 256 convinaciones, generalmente
solemos decir que este es el color, pero no es del todo
exacto, es el Nº de color en pantalla que en este modo solo
puede ser de 256C pero tenemos 262.144 colores para elegir,
esta es la paleta. Para cada uno de los 256 colores que podemos
tener en pantalla tenemos 18bits repartidos en 6 bits por
color básico ( Rojo,Verde,Azul), de esta forma por cada color
básico tenemos 2^6=64 grados de intensidad con lo que al
convinar los tres colores con los 18 bits tendremos
2^18=262.144 colores, si por cada uno de los 256 colores que
podemos tener en pantalla tenemos 3 bytes de los cuales solo
se utilizan los primeros 6 bits (0-5) entonces tendremos
3*256=768 bytes para la tabla de colores de este modo, esta es
la tabla de tonalidades del DAC ( Digital to Analog Converter)
los circuitos que convierten la señal digital de nuestro
ordenador (1bit= 0=0v,1=5v TTL) en analógica ( escalas de
tensión donde 1 byte o mas, como los 18bits se puede
representar por una sola línea en escalas de V) para que
podamos ver ese punto en nuestro monitor. Pues son esos 768
bytes los que tendremos que cambiar para poder ver los colores
originales de los sprites.
Los colores originales de los sprites los podemos
encontrar en los ficheros *.PAL que crea el programa Sprite
Maker al salvar la paleta.
Para cargarlos como siempre podemos optar por dos formas,
la primera seria cargando el fichero *.pal desde el disco por
vuestro programa utilizando el comando BLOCKREAD, exactamente
igual que con los sprites, y la segunda seria incluir la
paleta en nuestro programa convirtiéndola en un obj, no os voy
a explicar este proceso, porque es igual que lo ya explicado,
y como siempre tendremos que usar un puntero asociado a la
paleta, lo que si os voy a explicar es como llevar esta paleta
dentro de la tabla del DAC.
Para cargar la paleta en los registros del DAC vamos a
usar la interrupción 10 función 10 subfunción 12 para cargar
varios registros de color del DAC.
Las entradas en los registros del mp son:
AH=10h Que corresponde a la función.
AL=12H La subfunción.
BX= Número del primer registro de color direccionado
(0-255).
CX= Cantidad de registros a cargar.
ES= Dirección de segmento del Buffer.
Dx= Dirección de offset(o desplazamiento dentro del
segmento ) del Buffer.
Para cargar toda la paleta seria:
REG.AX:=$1012;
REG.BX:=$00;
REG.CX:=$100;
REG.ES:=SEG(PALETA); -> SEGMENTO
REG.DX:=OFS(PALETA); -> DESPLAZAMIENTO DENTRO DEL SEGMENTO.
INTR($10,REG);
Donde PALETA es un puntero que apunta al buffer, buffer
es la memoria donde esta los 768 bytes de la paleta, segmento
es el dato alto de la dirección del buffer, offset el dato
bajo de la dirección del buffer.
Para las personas que esten empezando con la programacion les
aconsejo que revisen los libros de ( Referencia al programador, Guia del
usuario, Guia del lenguaje ) que vienen con su compilador de Turbo Pascal,
prestar atención sobre todo en los temas relacionados con punteros.
Un libro que tambien os sera muy util es: PC INTERNO de Michael
Tischer, Data Becker edicion, Marcombo Boixareu editores.
Turbo Pascal y Turbo C son marcas registradas de Borland
International, Inc.
Para mas Información:
Enrique Sanchez Martinez
Apartado Nº 71 Barrio Issac Peral
CP:30300 Cartagena España (SPAIN)
O EN
--------------> BBS CLUB
2 LINEAS 14.400
CD ROM
(968) 201819
(968) 201262